/**
 * \file    item.cpp
 * \brief   Parser generator.
 * \author  Jérôme LAURENS
 * \version 0.1
 * \date    September 23, 2014
 *
 * Reads a LALR(1) grammar, generates a parser based on a template file.
 * This is based on lemon parser generator, but has strongly been
 * revisited.
 *
 */

#include <sstream>
#include <iostream>
#include "rule.h"
#include "symbol.h"
#include "item.h"

bool std::less<LPP_NAMESPACE_NAME::ItemWRef>::operator()(LPP_NAMESPACE_NAME::ItemWRef const & __lhs, LPP_NAMESPACE_NAME::ItemWRef const & __rhs) const {
    LPP_NAMESPACE_NAME::ItemRef const lhs = __lhs.lock();
    LPP_NAMESPACE_NAME::ItemRef const rhs = __rhs.lock();
    return lhs->id()<rhs->id();
//    return lhs<rhs;
}

size_t std::hash<LPP_NAMESPACE_NAME::ItemRef>::operator()(LPP_NAMESPACE_NAME::ItemRef const & x) const {
    return ::std::hash<LPP_NAMESPACE_NAME::SymbolIndex>()(x->dot())^::std::hash<LPP_NAMESPACE_NAME::Rule*>()(x->rule().get());
}

LPP_NAMESPACE_BEGIN

bool operator<(Item const & __lhs, Item const & __rhs) {
    return compare(__lhs,__rhs)<0;
}
bool operator==(Item const & __lhs,Item const & __rhs) {
    return compare(__lhs,__rhs)==0;
}
/* Compare two Items */
int compare(ItemWRef const & __lhs, ItemWRef const & __rhs) {
    return compare_WRef<ItemWRef>(__lhs,__rhs);
}
bool operator<(ItemWRef const & __lhs, ItemWRef const & __rhs) {
    return compare(__lhs,__rhs)<0;
}
bool operator==(ItemWRef const & __lhs,ItemWRef const & __rhs) {
    return compare(__lhs,__rhs)==0;
}

int compare(ItemRef const & __lhs, ItemRef const & __rhs) {
    return compare_Ref<ItemRef>(__lhs,__rhs);
}
bool operator<(ItemRef const & __lhs, ItemRef const & __rhs) {
    return compare(__lhs,__rhs)<0;
}
bool operator==(ItemRef const & __lhs,ItemRef const & __rhs) {
    return compare(__lhs,__rhs)==0;
}

/* Compare two Items */
int compare(Item const & __lhs, Item const & __rhs) {
    if (& __lhs == & __rhs) {
        return 0;
    }
#if 0
    if (__lhs.id()<__rhs.id()) return -1;
    if (__lhs.id()>__rhs.id()) return  1;
#else
    if (__lhs.rule()->id()<__rhs.rule()->id()) return -1;
    if (__lhs.rule()->id()>__rhs.rule()->id()) return  1;
    if (__lhs.dot()<__rhs.dot()) return -1;
    if (__lhs.dot()>__rhs.dot()) return  1;
#endif
    return 0;
}

String Item::short_description() const {
    RuleRef const & rule = this->rule();
    if (!rule) {
        return "None";
    }
    std::ostringstream oss;
    oss << rule->id() << ", "<< rule->index() << ", "<<dot_m;
    return oss.str();
}

String Item::description() const {
    std::ostringstream oss;
    RuleRef const & rule = this->rule();
    oss << rule->lhs_symbol()->name() << " ::=";
    SymbolIndex dot = this->dot();
    String dot_mark = " *";
    for (SymbolRef const & symbol: rule->rhs_symbols()) {
        if (dot--==0) {
            oss<<dot_mark;
            dot_mark = "";
        }
        if (symbol->is_multi_terminal()) {
            String sep = " ";
            for (SymbolRef const & S: symbol->get_sub_symbols()) {
                oss<<sep<<S->short_name();
                sep="|";
            }
        } else {
            oss<<" "<<symbol->short_name();
        }
    }
    oss<<dot_mark;
    return oss.str();
}

LPP_NAMESPACE_END

size_t std::hash<LPP_NAMESPACE_NAME::ItemWRef>::operator ()(LPP_NAMESPACE_NAME::ItemWRef const & __s) const {
    LPP_NAMESPACE_NAME::ItemRef s = __s.lock();
    return s? (size_t)(s.get()): 0;
}

